#include "GameEngine.h"

#include <cassert>

const player_t GameEngine::None = 0;
const player_t GameEngine::P1 = 1;
const player_t GameEngine::P2 = 2;

GameEngine::GameEngine():
m_currentPlayer(P1),
m_lastInstructionFailed(false),
m_inBallMove(false),
m_turnCount(0){
}

GameEngine::GameEngine(const Board& board, player_t currentPlayer, int turnCount):
m_board(board),
m_currentPlayer(currentPlayer),
m_lastInstructionFailed(false),
m_inBallMove(false),
m_turnCount(turnCount){
}

GameEngine::GameEngine(const GameEngine& from):
m_board(from.m_board),
m_currentPlayer(from.m_currentPlayer),
m_lastInstructionFailed(from.m_lastInstructionFailed),
m_inBallMove(from.m_inBallMove),
m_turnCount(from.m_turnCount){
}

bool GameEngine::step(const GameInput& gameInput){
	if(gameInput.action==GameInput::MOVEBALL){
		if(ballMoveIfCorrect(gameInput.place)){
			m_inBallMove = true;
			m_lastInstructionFailed = false;
		}else{
			m_lastInstructionFailed = true;
		}
		return !isGameOver();
	}else if(gameInput.action==GameInput::ENDMOVE){
		if(m_inBallMove){
			m_lastInstructionFailed = false;
			m_inBallMove = false;
			m_currentPlayer.change();
			++m_turnCount;
		}else{
			m_lastInstructionFailed = true;
		}
		return !isGameOver();
	}else{// Place pawn.
		if(m_inBallMove||!m_board.isPawnPlacable(gameInput.place)){
			m_lastInstructionFailed = true;
			return !isGameOver();
		}
		if(!m_board.setCase(gameInput.place,Board::CASE_PAWN)){
			assert(false);
			m_lastInstructionFailed = true;
			return !isGameOver();
		}
		m_lastInstructionFailed = false;
		m_currentPlayer.change();
		++m_turnCount;
		return !isGameOver();
	}
}

const Board& GameEngine::getBoard() const{
	return m_board;
}

player_t GameEngine::getCurrentPlayer() const{
	return m_currentPlayer;
}

bool GameEngine::getLastInputFailed() const{
	return m_lastInstructionFailed;
}

int GameEngine::getTurnCount() const{
	return m_turnCount;
}

bool GameEngine::isGameOver() const{
	return m_board.onGoalZone(m_board.getBallPosition())||m_turnCount>=turnLimit;
}

bool GameEngine::getWinner(player_t& winner) const{
	if(m_turnCount>=turnLimit){
		winner = None;
		return true;
	}
	if(m_board.onGoalZone(m_board.getBallPosition())){
		if(m_board.getBallPosition().x<=0){
			winner = P1;
		}else{
			winner = P2;
		}
		return true;
	}
	return false;
}

bool GameEngine::ballMoveIfCorrect(position_t dest){
	position_t ballPos = m_board.getBallPosition();
	if(ballPos==dest){
		return false;
	}
	vector_t direction = dest - ballPos;
	// Testing move.
	if(!direction.isDiagonalOrStraightLine()){
		return false;
	}
	direction = direction.normalized();
	position_t caseToCheck = ballPos + direction;
	if(caseToCheck==dest){
		return false;// Not jumping over a least one pawn.
	}
	while(caseToCheck != dest){
		if(m_board.getCase(caseToCheck)!=Board::CASE_PAWN){
			return false;
		}
		caseToCheck = caseToCheck + direction;
	}
	if(m_board.getCase(caseToCheck)!=Board::CASE_EMPTY
		&& !m_board.onGoalZone(caseToCheck)){
		return false;
	}
	// Second loop to remove the pawns.
	caseToCheck = ballPos + direction;
	while(caseToCheck != dest){
		m_board.setCase(caseToCheck,Board::CASE_EMPTY);
		caseToCheck = caseToCheck + direction;
	}
	return m_board.setBallPosition(dest);
}